#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "usim_drv.h"
#include "common.h"
#include "usim_process.h"
#include "p_lib.h"
#include "xm_client.h"

int USIM_MF_EF_SFI_Num = 0;//
int USIM_MF_DF_EF_SFI_Num = 0;
int USIM_ADF_EF_SFI_Num = 0x18;//
int USIM_ADF_DF_EF_SFI_Num = 0;//
extern Common_Data Data;
extern int Fd;
unsigned char LastRand[64] = {'\0'};

SFI_LIST USIM_ADF_EF_SFI_DEFAULT_LIST[]={
	{0x01, 0x6FB7},
	{0x02, 0x6F05},
	{0x03, 0x6FAD},
	{0x04, 0x6F38},
	{0x05, 0x6F56},
	{0x06, 0x6F78},
	{0x07, 0x6F07},
	{0x08, 0x6F08},
	{0x09, 0x6F09},
	{0x0A, 0x6F60},
	{0x0B, 0x6F7E},
	{0x0C, 0x6F73},
	{0x0D, 0x6F7B},
	{0x0E, 0x6F48},
	{0x0F, 0x6F5B},
	{0x10, 0x6F5C},
	{0x11, 0x6F61},
	{0x12, 0x6F31},
	{0x13, 0x6F62},
	{0x14, 0x6F80},
	{0x15, 0x6F81},
	{0x16, 0x6F4F},
	{0x17, 0x6F06},
	{0x18, 0x6F65},
};

SFI_LIST USIM_ADF_EF_SFI_LIST[MAX_ADF_EF_SFI_LIST];

unsigned char AID[MAX_FILE_CODE_LEN];		//ID of Application
unsigned char AID_Len;
unsigned char SH_AID_FCP[100];
int SH_AID_FCP_LEN = 0;

/*=====================================================
FCP TLV ANL
return the number of EF properties
=======================================================*/
static int VUSIM_TLV_ANL( tlv_def * Dst, unsigned char *srcbuf)
{
	unsigned char TAGG = 0;
	unsigned char LEN = 0;
	unsigned char * p_temp = srcbuf;
	int cnt = 0;
	tlv_def * p_tlv = Dst;
	int Ret = 0;
	TAGG = *(p_temp++);
	LEN = *(p_temp++);
	do{
		p_tlv->tag = *(p_temp++);
		p_tlv->len = *(p_temp++);
		memcpy(p_tlv->value,p_temp,p_tlv->len);
		p_temp += p_tlv->len;
		cnt += (2+p_tlv->len);
		p_tlv++;
		Ret++ ;
	}while(cnt<LEN);

	return Ret;
}

static int VUSIM_GET_SFI(VUSIM_STA *sta, tlv_def * Src, int tlv_Num)
{
	tlv_def *p_src = Src;
	SFI_LIST *p_dst = NULL;
	int FID = 0;
	unsigned char SFI = 0 ;
	int *p_SFI_Num = NULL;
	int i;

	//search tag_sfi in anl_FCP
	for (i = 0;i < tlv_Num; i++)
	{
		if(TAG_FILE_ID == p_src->tag)//save file id
		{
			FID = p_src->value[0];
			FID = (FID << 8);
			FID += (int)(p_src->value[1]);
		}

		if(TAG_SFI == p_src->tag)
		{
			if(0 == p_src->len)
				return 1;
			else
				break;
		}
		p_src++;
	}

	switch(sta->Current_DFType)
    {
        case USIM_ADF_EF:
        case USIM_ADF_DF:
            p_dst     =   USIM_ADF_EF_SFI_LIST;
            p_SFI_Num = (&USIM_ADF_EF_SFI_Num);
            break;
        default:
            return 3;
            break;
    }

	//judge if the sfi already exist
	SFI = ((p_src->value[0])>>3);
	i = 0;

	do{
		if(SFI == (p_dst->SF))
		{
			break;
		}
		p_dst++;
		i++;
	}while(i<(*p_SFI_Num));

	//generat sfi list
	if(i >(*p_SFI_Num))//
	{
		p_dst->SF = SFI;//write SFI
		p_dst->FID = FID;
		(*p_SFI_Num)++;
		DBUG("simctrl:GET_SFI NEW SFI saved to SFI List\n");
		return 0;
	}

	return 2;
}

static int VUSIM_FILE_SEARCH(VUSIM_STA *sta)
{
	int i=0;
	int Fcb_NUM;
	FILE_CONTROL_BLOCK *Temp_FCB;
	int Fcp_pointer = 0;
	int Fct_pointer = 0;
	int status = 0;
	int DF_Type = NOT_USIM_FILE;
	Fcb_NUM  = Data.File_FCB[0];
	Temp_FCB = (FILE_CONTROL_BLOCK *)(Data.File_FCB + 1);

	do{
		if((0 == memcmp(sta->code, Temp_FCB->code, Temp_FCB->code_len))
			&&((sta->code_len) == (Temp_FCB->code_len)))
		{
			//DBUG("simctrl:file %s found\n",Temp_FCB->comments);
			break;
		}
		Temp_FCB++;
		i++;
	}while(i<Fcb_NUM);

	Fcp_pointer = (int)(Temp_FCB->FCP_pointerH);
	Fcp_pointer = (Fcp_pointer<<8);
	Fcp_pointer |= (int)(Temp_FCB->FCP_pointerL);

	Fct_pointer = (int)(Temp_FCB->content_pointerH);
	Fct_pointer = (Fct_pointer<<8);
	Fct_pointer |= (int)(Temp_FCB->content_pointerL);

	DF_Type = (int)(Temp_FCB->typeH);
	DF_Type = (DF_Type<<8);
	DF_Type |= (int)(Temp_FCB->typeL);

	if(i >= Fcb_NUM)
	{
		sta->FCP_point = 0;
		sta->FCP_len   = 0;
		sta->FCT_point = 0;
		sta->FCT_len   = 0;
		sta->SW[0]     = SW1_FILE_DONT_EXIST;
		sta->SW[1]     = SW2_FILE_DONT_EXIST;
		status = 1;
	}
	else
	{
		sta->FCP_point = Fcp_pointer;
		sta->FCP_len   = (int)(Temp_FCB->FCP_len);
		sta->FCT_point = Fct_pointer;
		sta->FCT_len   = Temp_FCB->content_len;
		sta->SW[0]     = SW1_OK_WITH_Le;
		sta->SW[1]     = Temp_FCB->FCP_len;
		sta->Current_DFType = DF_Type;
	}

	return status;
}

static int VUSIM_FCP_search(VUSIM_STA *sta, u8 *buf)
{
	unsigned char *TXBuf = Data.File_FCP;
	tlv_def Temp_tlv[20];
	unsigned char Cnt_tlv = 0 ;

	if(0 == sta->FCP_len)
		return 1;

	TXBuf += (sta->FCP_point);

	memcpy(buf, TXBuf, sta->FCP_len);
	if((0x7f == sta->code[0])&&(0xff == sta->code[1])&&(0x02 == sta->code_len))
	{
		SH_AID_FCP_LEN = sta->FCP_len;
		memcpy(SH_AID_FCP, TXBuf, SH_AID_FCP_LEN);
	}

	if(USIM_ADF_EF == sta->Current_DFType || USIM_MF_DF == sta->Current_DFType)//add by 20160804
	{
		//tlv analisys
		Cnt_tlv = VUSIM_TLV_ANL(Temp_tlv, buf);
		//sfi list generat
		VUSIM_GET_SFI(sta, Temp_tlv, Cnt_tlv);
	}

	return 0;
}

static int VUSIM_FCT_search(VUSIM_STA *sta, u8 *buf)
{
	unsigned char *TXBuf = Data.File_FCT;
	if(0 == sta->FCT_len)
		return -1;

	//ust special process
	TXBuf += (sta->FCT_point);
	memcpy(buf, TXBuf, sta->FCT_len);

	return 0;
}

/*
function name : VUSIM_SFI_search
Description: short file id find EF
input:SF
output:RET : 0-file found  1-file not found
VUSIM_STA vusim will be changed
*/
static int VUSIM_SFI_search(VUSIM_STA *vusim, unsigned char SF)
{
	SFI_LIST * p_sfi;
	unsigned char * p_code;
//	DBUG( "This come from %s the SF is %02x\n", __func__, SF);

	switch(vusim->Current_DFType)
    {
        case USIM_ADF_EF:
        case USIM_ADF_DF:
            p_code = (2 + vusim->code);
            p_sfi = USIM_ADF_EF_SFI_LIST;
            break;
        default:
            DBUG("SFI_search:Current FileType=%04x do not support SFI\n",vusim->Current_DFType);
            return 1;
            break;
    }

	do{
		if(SF == p_sfi->SF)
		{
			memcpy(p_code, &(p_sfi->FID), 2);
			//�ļ�ID����
			(*p_code)  = (((*p_code))^((*(p_code + 1))));
			*(p_code + 1) = (((*p_code))^((*(p_code + 1))));
			(*p_code)   = (((*p_code))^((*(p_code + 1))));

			if(VUSIM_FILE_SEARCH(vusim))
			{
				return 1;
			}
			return 0;
		}
		p_sfi++;

	}while((0xFF != p_sfi->SF)&&(0xFFFF != p_sfi->FID));

	vusim->SW[0] = 0x6A;
	vusim->SW[1] = 0x82;

	return 1;
}

static void VUSIM_APDU_SELECTFILE2(unsigned char* RecvBuf, int RecvLen, APDU_HEAD * head ,VUSIM_STA * VS)
{
	int status = 0;
	unsigned char Buf[256]={0};

	status = VSIM_APDU_Para_Test(RecvBuf, RecvLen, head, 500);
	if(status < 0)
		return;

	memcpy(Buf, head, 5);
	memcpy(Buf + 5, RecvBuf, head->LcLe);
	//PrintDebuf("C=", Buf, 5+head->LcLe);

	if(0x04 == head->P1)//modify by 20160804
	{
		memcpy(AID, RecvBuf, RecvLen); //updata AID
		AID_Len = RecvLen;

        if(VS->USAT_Flag)
		{
			VS->SW[0] = Data.USAT_SW1;
			VS->SW[1] = Data.USAT_SW2;
		}
		else
		{
			VS->SW[0] = SW1_OK_WITHOUT_Le;
			VS->SW[1] = SW2_OK_WITHOUT_Le;
		}
/*
        00 A4 04 04 10 A4 A0 00 00 00 87 10 02 FF 86 FF 03 89 FF FF FF FF
        61 2E
        00 C0 00 00 2E
        C0 62 2C 82 02 78 21 84 10 A0 00 00 00 87 10 02 FF 86 FF 03 89 FF FF FF FF 8A 01 05 8B 03 2F 06 02 C6 0C 90 01 60 83 01 01 83 01 81 83 01 0A 90 00
        80 14 00 00 0C 14 81 03 01 25 00 02 02 82 81 83 01 00 91 0E 80 12 00 00 0E 12 D0 0C 81 03 01 05 00 82 02 81 82 19 01 03 90 00
        80 14 00 00 0C 14 81 03 01 05 00 02 02 82 81 03 01 00 90 00
        01 A4 04 00 09 A4 A0 00 00 01 51 44 41 43 00
        6A 82
        01 A4 00 04 02 A4 3F 00
        61 29
        01 C0 00 00 29
        C0 62 27 82 02 78 21 83 02 3F 00 A5 07 80 01 71 C0 02 00 01 8A 01 05 8B 03 2F 06 02 C6 0C 90 01 60 83 01 01 83 01 81 83 01 0A 90 00
*/
        if(0x10 == head->LcLe)
        {
            VS->SW[0] = 0x61;
            VS->SW[1] = 0x2E;
        }

	}
	else
	{
		memcpy(VS->code, RecvBuf, RecvLen);
        VS->code_len = head->LcLe;

		if(RecvLen != head->LcLe)
		{
			VS->SW[0] = SW1_FILE_DONT_EXIST;
        	VS->SW[1] = SW2_FILE_DONT_EXIST;
		}

		VUSIM_FILE_SEARCH(VS);
	}

    //PrintDebuf("R=", VS->SW, 2);
	VUSIM_RetData(VS->SW, 2);
	(VS->APDU_STAGE) = APDU_STAGE0;

	return ;
}

static int VUSIM_APDU_GETRESPONSE(APDU_HEAD * head ,VUSIM_STA * VS)
{
	int status = 0;
	unsigned char  tmp[100];
	//Sim_Log_Hex("C=", (unsigned char *)head, 5);

	if(VS->Authenticate_Flag) //Authenticate
	{
		VS->Authenticate_Flag = 0;//FALSE;
		memcpy(VS->TXbuf, Data.g_TT_ctl.RcvBuf, Data.g_TT_ctl.Rcv_Len);
		VS->TX_len = Data.g_TT_ctl.Rcv_Len;
		DBUG("the Rcv_Len is %d\n", Data.g_TT_ctl.Rcv_Len);
		VS->APDU_STAGE = APDU_STAGE0;
		//Sim_Log_Hex("R=", VS->TXbuf, VS->TX_len);
		VUSIM_RetData(VS->TXbuf+1, VS->TX_len-1);

		return 0;
	}

	if(VS->Status_Flag)//status
	{
		VS->TXbuf[0] = TAG_AID_IND;
		VS->TXbuf[1] = AID_Len;
		memcpy( 2+VS->TXbuf, AID, AID_Len);
		VS->TX_len = (AID_Len+2);
	}
	else //normal get response
	{
		status = VUSIM_FCP_search(VS, VS->TXbuf);//it's need judge here
		VS->TX_len = head->LcLe;
	}

	//VUSIM_ReProcessByte(head->INS);

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}

	memcpy(((VS->TX_len) + VS->TXbuf), VS->SW, 2);
	(VS->TX_len) += 2;
	//Sim_Log_Hex("R=", VS->TXbuf, VS->TX_len);

//	memset(tmp, 0, 100);
//	memcpy(tmp, &head->INS, 1);
//	memcpy(tmp+1, VS->TXbuf, VS->TX_len);
//    VS->TX_len += 1;
//	memcpy(VS->TXbuf, tmp, VS->TX_len);
/*
	00 A4 04 04 10 A4 A0 00 00 00 87 10 02 FF 86 FF 03 89 FF FF FF FF
	61 2E
	00 C0 00 00 2E
	C0 62 2C 82 02 78 21 84 10 A0 00 00 00 87 10 02 FF 86 FF 03 89 FF FF FF FF 8A 01 05 8B 03 2F 06 02 C6 0C 90 01 60 83 01 01 83 01 81 83 01 0A 90 00
	80 14 00 00 0C 14 81 03 01 25 00 02 02 82 81 83 01 00 91 0E 80 12 00 00 0E 12 D0 0C 81 03 01 05 00 82 02 81 82 19 01 03 90 00
	80 14 00 00 0C 14 81 03 01 05 00 02 02 82 81 03 01 00 90 00
*/
	unsigned char buff[]={0x62, 0x2C, 0x82, 0x02, 0x78, 0x21 ,0x84 ,0x10 ,0xA0 ,0x00 ,0x00 ,0x00 ,0x87 ,0x10 ,0x02 ,0xFF ,0x86 ,0xFF ,0x03 ,0x89 ,\
	                      0xFF ,0xFF ,0xFF ,0xFF ,0x8A ,0x01 ,0x05 ,0x8B ,0x03 ,0x2F ,0x06 ,0x02 ,0xC6 ,0x0C ,0x90 ,0x01 ,0x60 ,0x83 ,0x01 ,0x01 ,\
	                      0x83 ,0x01 ,0x81 ,0x83 ,0x01 ,0x0A ,0x90 ,0x00};
	if(head->LcLe == 0x2E)
	{
		VS->TX_len = 48;
		memcpy(VS->TXbuf, buff, VS->TX_len);
	}

	VUSIM_RetData(VS->TXbuf, VS->TX_len);
	VS->APDU_STAGE = APDU_STAGE0;

	return status;
}

static void VUSIM_APDU_READ(APDU_HEAD * head ,VUSIM_STA * VS)
{
	//Sim_Log_Hex("C=",(unsigned char *)head, 5);

	if(READ_RECORD==head->INS)
	{
		VUSIM_FILE_SEARCH(VS);
		VS->FCT_point += ((int)(((head->P1)-1)*(head->LcLe)));
	}

	if((READ_BINARY==head->INS)&&((head->P1)&0x80))
	{
		if(VUSIM_SFI_search(VS,((head->P1)&0x1F)))//file not find
		{
			VS->APDU_STAGE = APDU_STAGE0;
			VS->SW[0] = SW1_FILE_DONT_EXIST;
			VS->SW[1] = SW2_FILE_DONT_EXIST;
			VUSIM_RetData(VS->SW, 2);
			//Sim_Log_Hex("R=",VS->SW, 2);
			return ;
		}
	}

	VS->FCT_len = head->LcLe; //malysia 20150427

	if(VUSIM_FCT_search(VS, VS->TXbuf))
	{
		DBUG("simctrl:FCT search err");
		VS->SW[0] = 0x64;
		VS->SW[1] = 0x00;
		VS->APDU_STAGE = APDU_STAGE0;
		//Sim_Log_Hex("R=",VS->SW, 2);
		VUSIM_RetData(VS->SW, 2);
		return ;
	}

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}

	//VUSIM_ReProcessByte(head->INS);
	VS->APDU_STAGE = APDU_STAGE0;
	memcpy(((VS->FCT_len)+VS->TXbuf),VS->SW,2);
	//Sim_Log_Hex("R=", VS->TXbuf, 2+head->LcLe);
	VUSIM_RetData(VS->TXbuf, 2 + head->LcLe);//20150106 for Thiland test

	return ;
}

static void VUSIM_APDU_VERIFY(APDU_HEAD * head ,VUSIM_STA * VS)
{
	//Sim_Log_Hex("C=",(unsigned char*)head, 5);
	VS->SW[0]=0x63;
	VS->SW[1]=0xC3;
	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=",VS->SW, 2);
	VUSIM_RetData(VS->SW,2);
	return ;
}

static void VUSIM_APDU_UNBLOCK(APDU_HEAD * head ,VUSIM_STA * VS)
{
	//Sim_Log_Hex("C=", (unsigned char *)head, 5);
	VS->SW[0]=0x63;
	VS->SW[1]=0xCA;
	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=",VS->SW, 2);
	VUSIM_RetData(VS->SW,2);

	return ;
}

static void VUSIM_APDU_TERMINAL_PROFILE2(unsigned char *RecvBuf, int iRecvLen, APDU_HEAD * head ,VUSIM_STA * VS)
{
	int status = 0;
	unsigned char Buf[256]={0};

	status = VSIM_APDU_Para_Test(RecvBuf, iRecvLen, head, 50);
	if(status < 0)
		return;

	memcpy(Buf, (unsigned char *)head, 5);
	memcpy(Buf+5, RecvBuf, head->LcLe);
	//Sim_Log_Hex("C=",Buf, 5+head->LcLe);
	VS->SW[0] = Data.USAT_SW1;
	VS->SW[1] = Data.USAT_SW2;
	//Sim_Log_Hex("R=",VS->SW,2);
	VUSIM_RetData(VS->SW,2);
	VS->APDU_STAGE = APDU_STAGE0;

	return ;
}

static void VUSIM_APDU_STATUS(APDU_HEAD * head ,VUSIM_STA * VS)
{
	unsigned char * p_tx;
	p_tx = VS->TXbuf;

	VS->TX_len = 0;
	if((1==head->P2)&&(head->LcLe == (AID_Len+2) ))
	{
		VS->TX_len = AID_Len;
		memcpy(p_tx , AID , AID_Len);
		p_tx += AID_Len;
		if(VS->USAT_Flag)
		{
			*(p_tx++) = Data.USAT_SW1;
			*(p_tx++) = Data.USAT_SW2;
		}
		else
		{
			*(p_tx++) = SW1_OK_WITHOUT_Le;
			*(p_tx++) = SW2_OK_WITHOUT_Le;
		}
		VS->Status_Flag=0;//FALSE;
	}
	else if(0 == head->LcLe) //80 f2 00 00 00
	{
		if(0x0C == head->P2)//80 F2 01 0C 00
		{
			*(p_tx++) = Data.USAT_SW1;
			*(p_tx++) = Data.USAT_SW2;
		}
		else
		{
			*(p_tx++) = 0x6C;
			*(p_tx++) = SH_AID_FCP_LEN;
		}
	}
	else if(SH_AID_FCP_LEN == head->LcLe) //80 f2 00 00 xx
	{
		//VUSIM_ReProcessByte(head->INS);
		VS->TX_len = SH_AID_FCP_LEN;
		memcpy(p_tx,SH_AID_FCP,VS->TX_len);
		p_tx += VS->TX_len;
		*(p_tx++) = SW1_OK_WITHOUT_Le;
		*(p_tx++) = SW2_OK_WITHOUT_Le;
	}
	VS->APDU_STAGE = APDU_STAGE0;
	VUSIM_RetData(VS->TXbuf, (2 + VS->TX_len));

	return ;
}

//CHOWN -R
static void VUSIM_APDU_FETCH(APDU_HEAD * head ,VUSIM_STA * VS)
{
	unsigned char * p_tx = VS->TXbuf;
	VS->USAT_Flag = 0;//FALSE;
	//Sim_Log_Hex("C=",(unsigned char *)head,5);
	if((Data.FCH_Size)!=head->LcLe)
	{
		*(p_tx++) = 0x68;
		*(p_tx++) = 0x00;
		VS->TX_len = 0;
	}
	else
	{
		memcpy(p_tx, Data.File_FCH, Data.FCH_Size);
		p_tx += Data.FCH_Size ;
		VS->TX_len =  Data.FCH_Size;
		*(p_tx++) = SW1_OK_WITHOUT_Le;
		*(p_tx++) = SW2_OK_WITHOUT_Le;
	}

	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=",VS->TXbuf,2+VS->TX_len);
	VUSIM_RetData(VS->TXbuf,2+VS->TX_len);

	return ;
}

static void VUSIM_APDU_TRESPONSE2(unsigned char *RecvBuf, int iRecvLen, APDU_HEAD * head, VUSIM_STA * VS)
{
	int status = 0;
	unsigned char Buf[256]={0};

	status = VSIM_APDU_Para_Test(RecvBuf, iRecvLen, head, 50);
	if(status < 0)
		return;

	memcpy(Buf, (unsigned char *)head, 5);
	memcpy(Buf+5, RecvBuf, head->LcLe);
	//Sim_Log_Hex("C=",Buf, 5+head->LcLe);

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}
	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=",VS->SW,2);
	VUSIM_RetData(VS->SW,2);

	return ;
}

static int VUSIM_AUTH_ResultCh_3G(unsigned char * buf, int iLen)
{
	unsigned char Tag = 0;
	unsigned char RES_Len=0;
	unsigned char Result[128]={0};
	unsigned char CK_Len =0;
	unsigned char IK_Len = 0;
	unsigned char Kc_Len=0;
	unsigned char *p_RES,*p_CK,*p_IK,*p_Kc,*p;

	Tag = buf[1];
	memset(Result,0,128);
	memcpy(Result, buf+2, iLen);
	p = Result;
	if(Tag == 0xDB)
	{
		RES_Len = *p;
		p++;
		p_RES = p;
		p += RES_Len;

		CK_Len = *p;
		p++;
		p_CK = p;
		p += CK_Len;

		IK_Len = *p;
		p++;
		p_IK = p;
		p += IK_Len;

		Kc_Len = *p;
		p++;
		p_Kc = p;

		//Debuf_Print_Data(p_RES, RES_Len, "Res is:");
		//Debuf_Print_Data(p_CK, CK_Len, "CK is:");
		//Debuf_Print_Data(p_IK, IK_Len, "IK is:");
		//Debuf_Print_Data(p_Kc, Kc_Len, "Kc is:");

		if(Kc_Len == 0)
		{
			DBUG(" no KC in tt result\n");
			return iLen;
		}
		else
		{
			if((iLen-4)!=(RES_Len + CK_Len + IK_Len + Kc_Len + 4))
			{
				DBUG("TT result format fault\n");
				buf[0]=0x6F;
				buf[1]=0x00;
				return 2;
			}
			return iLen;
		}
	}
	else if(Tag == 0xDC)
	{
		return iLen;
	}
	DBUG("TT result format fault buf[0]=%02x\n",Tag);
	buf[0] = 0x6F;
	buf[1] = 0x00;
	return 2;
}

static int VUSIM_AUTH_ResultCh_GSM(unsigned char * buf, int iLen)
{
	#if 0
	if(17 != iLen)
	{
		DBUG("[VUSIM_AUTH_ResultCh_GSM]:TT result format fault\n");
		buf[0]=0x6F;
		buf[1]=0x00;
		return 2;
	}
	else
	{
		return iLen;
	}
	#endif
	return iLen;
}

static int VUSIM_AUTH_ResultCheck(APDU_HEAD * head, unsigned char *buf, int iLen)
{
	int retVal = 0;
	unsigned char type = (head->P2 & 0x0F);

	if((0x88 != head->INS)||(buf == NULL)||(iLen <= 0))
	{
		DBUG("[VUSIM_AUTH_ResultCheck]Para error head->INS=%02x,iLen=%d\n",head->INS,iLen);
		return -1;
	}

	if((buf[0] != 0xC0)||(buf[iLen-1] != 0x00)||(buf[iLen-2] != 0x90))
	{
		DBUG("[VUSIM_AUTH_ResultCheck]:buf[0]=%02x,buf[iLen-2]=%02x,buf[iLen-1]=%02x\n",buf[0],buf[iLen-2]),buf[iLen-1];
		return -2;
	}

	switch(type)
	{
		case 0://GSM auth
			retVal = VUSIM_AUTH_ResultCh_GSM(buf, iLen);
			break;
		case 1://3G auth
			retVal = VUSIM_AUTH_ResultCh_3G(buf, iLen);
			break;
		default:
			DBUG( "[VUSIM_AUTH_ResultCheck]head error %02x %02x %02x %02x %02x\n", head->CLA, head->INS, head->P1, head->P2, head->LcLe);
			retVal = -2;
			break;
	}

	return retVal;
}

static int VUSIM_Auth_Data_Snd(unsigned char *pData, int iLen, unsigned char *Head)
{
    pid_t pid = getpid();
    struct timeval cur_time;

    int status = 0;
    unsigned char Buf[256] = {0};
    TT_Ctl_t *p_ctl = &Data.g_TT_ctl ;

    //PrintDebuf("TT :", pData, iLen);

    if((iLen <= 0)||(pData == NULL)||(Head == NULL))
    {
        DBUG( "Para error\n");
        return -1;
    }

    if(0 == memcmp(LastRand, pData, iLen))
        DBUG( "the rand is the same as last one\n");
	else
    	(p_ctl->Snd_Cnt) ++;//modify by 20161031

    memcpy(LastRand, pData, iLen);

    status = TT_Dat_Pack1(pData, iLen, Head, Buf);

    //PrintDebuf("TT2 :", Buf, status);

    p_ctl->Snd_Len = TT_Dat_Pack2(Buf, status, p_ctl->Snd_Cnt, p_ctl->SndBuf);
    //PrintDebuf("TT data send to server is:", p_ctl->SndBuf, p_ctl->Snd_Len);

    p_ctl->flag = TRANSFER_TRANSPARENT_START;
    p_ctl->Rcv_Len = 0;
    memset(p_ctl->RcvBuf , 0, sizeof(p_ctl->Rcv_Len));

    gettimeofday(&cur_time, NULL);
    memcpy(&(p_ctl->snd_time), &cur_time, sizeof(cur_time));

    //kill(pid, SIGRTMIN); //notice socket to send tt data
    TT_Process_t(&SysCtl);

    return 1;
}

static void VUSIM_Auth_Data_Recv(void)
{
    TT_Ctl_t *p_ctl = &Data.g_TT_ctl ;
    int i = 0 ;
    struct timeval cur_time;
    long misends = 0;

	do{
        if(TRANSFER_TRANSPARENT_OVER == p_ctl->flag)
        {
            Data.g_TT_Success_time = time(NULL);
            break;
        }
        Delay(0, 5);
        i++;
    }while(i < 15000);

	DBUG("iiiiiiiiiiiiiiiiiii=%d", i);

    gettimeofday(&cur_time, NULL);
    misends = (cur_time.tv_sec - p_ctl->snd_time.tv_sec)*1000 + (cur_time.tv_usec - p_ctl->snd_time.tv_usec)/1000;
    DBUG( "VUSIM time spend on socket is %ld ms\n", misends);

    if(misends >= 7500)
	{
        p_ctl->Rcv_Len = 0;
		memset(p_ctl->RcvBuf, 0, sizeof(p_ctl->RcvBuf));
		p_ctl->RcvBuf[0] = 0x6F;
		p_ctl->RcvBuf[1] = 0x00;
	}

    DBUG("TTTTTTTTTTT cnt=%d: %d bytes snd to MiFi TTTTTTTTTTTT\n", p_ctl->Snd_Cnt, p_ctl->Rcv_Len);
	PrintDebuf("Data snd to mifi is", p_ctl->RcvBuf, p_ctl->Rcv_Len);

    p_ctl->flag = TRANSFER_TRANSPARENT_IDEL;

    return;
}

static void VUSIM_APDU_AUTHENTICATE2(unsigned char *RecvBuf, int iRecvLen, APDU_HEAD *head, VUSIM_STA *VS, int *flag)
{
	int send_cnt = 0;
	int status = 0;
	unsigned char Buf[256] = {0};

	status = VSIM_APDU_Para_Test(RecvBuf, iRecvLen, head, 50);
	if(status < 0)
		return;

	memcpy(Buf, head, 5);
	memcpy(Buf+5, RecvBuf, head->LcLe);
	//Sim_Log_Hex("C=", Buf, 5 + head->LcLe);

	send_cnt = VUSIM_Auth_Data_Snd(RecvBuf, head->LcLe, (unsigned char *)head);
	if(0 < send_cnt)
	{
		VUSIM_Auth_Data_Recv();
		status = VUSIM_AUTH_ResultCheck(head, Data.g_TT_ctl.RcvBuf, Data.g_TT_ctl.Rcv_Len);//?????
	}
	else
	{
		Data.g_TT_ctl.RcvBuf[0] = 0x6F;
		Data.g_TT_ctl.RcvBuf[1] = 0x00;
		Data.g_TT_ctl.Rcv_Len = 2;
	}

	if(status > 3)// auth success
	{
		VS->Authenticate_Flag = 1;//TRUE;
		VS->TXbuf[0] = 0x61;
		VS->TXbuf[1] = (Data.g_TT_ctl.Rcv_Len - 3);
		VS->TX_len = 2;
		//Sim_Log_Hex("R=", VS->TXbuf, VS->TX_len);
	}
	else if(status == 2)
	{
		VS->Authenticate_Flag = 1;//TRUE;
		VS->TXbuf[0] = 0x98;
		VS->TXbuf[1] = 0x62;
		VS->TX_len = 2;
		//Sim_Log_Hex("R=", VS->TXbuf, VS->TX_len);
	}
	else
		VS->TX_len = 0;

	VUSIM_RetData(VS->TXbuf, VS->TX_len);
	VS->APDU_STAGE = APDU_STAGE0;

	return ;
}

static void VUSIM_APDU_UPDATE1(APDU_HEAD * head ,VUSIM_STA * VS)
{
	int status = 0;

	DBUG("simctrl:binary update recieved\n");
	VUSIM_ReProcessByte(head->INS);
	VS->APDU_STAGE = APDU_STAGE1;

	return ;
}

static void VUSIM_APDU_UPDATE2(unsigned char *RecvBuf, int iRecvLen, APDU_HEAD * head ,VUSIM_STA * VS)
{
	int status = 0;
	unsigned char Buf[256]={0};
	unsigned char EF_PLMN[4] = {0x7F, 0xFF, 0x6F, 0x7B};

	status = VSIM_APDU_Para_Test(RecvBuf, iRecvLen, head, 500);
	if(status < 0)
		return;

	memcpy(Buf, (unsigned char *)head, 5);
	memcpy(Buf+5, RecvBuf, head->LcLe);
	//Sim_Log_Hex("C=",Buf, 5+head->LcLe);

	if(memcmp(EF_PLMN, VS->code, 4))//6f 7b do not update FPLMN 2016.02.25
	{
		VUSIM_FCT_UPDATE(VS, RecvBuf, head->LcLe);
	}
	else
	{
		DBUG("do not update fplmn\n");
	}

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}
	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=",VS->SW,2);
	VUSIM_RetData(VS->SW,2);

	return ;
}

static void VUSIM_APDU_MANAGE_CHANNEL_PROC1(APDU_HEAD * head ,VUSIM_STA * VS)
{
	unsigned char Buf[64] = {'\0'};
	//DBUG( "%s:MANAGE_CHANNEL recieved\n", __func__);
	VUSIM_ReProcessByte(head->INS);

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}

	VUSIM_RetData(Buf, 1);//??? why
	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=", VS->SW, 2);
	VUSIM_RetData(VS->SW, 2);

	return ;
}

static void VUSIM_APDU_MANAGE_CHANNEL_PROC2(unsigned char *RecvBuf, int iRecvLen, APDU_HEAD * head, VUSIM_STA * VS)
{
	int status = 0;
	unsigned char Buf[256]={0};
	unsigned char EF_PLMN[4] = {0x7F, 0xFF, 0x6F, 0x7B};

	status = VSIM_APDU_Para_Test(RecvBuf, iRecvLen, head, 500);
	if(status < 0)
		return;

	memcpy(Buf, (unsigned char *)head, 5);
	memcpy(Buf+5, RecvBuf, head->LcLe);
	//Sim_Log_Hex("C=", Buf, 5+head->LcLe);

	if(VS->USAT_Flag)
	{
		VS->SW[0] = Data.USAT_SW1;
		VS->SW[1] = Data.USAT_SW2;
	}
	else
	{
		VS->SW[0] = SW1_OK_WITHOUT_Le;
		VS->SW[1] = SW2_OK_WITHOUT_Le;
	}

	VS->APDU_STAGE = APDU_STAGE0;
	//Sim_Log_Hex("R=", VS->SW, 2);
	VUSIM_RetData(VS->SW, 2);

	return ;
}

static void VUSIM_APDU_PROC1(APDU_HEAD * head ,VUSIM_STA * VS)
{
	switch(head->INS)
	{
		case SELECT_FILE:
			APDU_Send_Byte_Ins(head, VS);
			break;

		case GET_RESPONSE:
			VUSIM_APDU_GETRESPONSE(head,VS);
			break;

		case READ_BINARY:
		case READ_RECORD:
			VUSIM_APDU_READ(head,VS);
			break;

		case VERIFY:
			VUSIM_APDU_VERIFY(head,VS);
			break;

		case UNBLOCK_PIN:
			VUSIM_APDU_UNBLOCK(head,VS);
			break;

		case TERMINAL_PROFILE:
			VS->USAT_Flag=1;//TRUE;
			APDU_Send_Byte_Ins(head, VS);
			break;

		case STATUS:
			VUSIM_APDU_STATUS(head,VS);
			break;

		case FETCH:
			VUSIM_APDU_FETCH(head,VS);
			break;

		case TERMINAL_RESPONSE:
			APDU_Send_Byte_Ins(head, VS);
			break;

		case INTERNAL_AUTHENTICATE:
			APDU_Send_Byte_Ins(head, VS);
			break;

		case UPDATE_BINARY:
		case UPDATE_RECORD:
			VUSIM_APDU_UPDATE1(head,VS);
			break;
		case MANAGE_CHANNEL:
			VUSIM_APDU_MANAGE_CHANNEL_PROC1(head,VS);
			break;
		default:
			DBUG("[VUSIM_APDU_PROC1]ERROR DATA INS:%d\n", head->INS);//YYH TEST
			break;
	}

	return;
}

static void VUSIM_APDU_PROC2(unsigned char *RcvBuf, int iRecvLen, APDU_HEAD * head, VUSIM_STA *VS, int *flag)
{
	switch(head->INS)
	{
		case SELECT_FILE:
			VUSIM_APDU_SELECTFILE2(RcvBuf, iRecvLen, head,VS);
			break;
		case TERMINAL_PROFILE:
			VUSIM_APDU_TERMINAL_PROFILE2(RcvBuf, iRecvLen, head,VS);
			break;
		case TERMINAL_RESPONSE:
			VUSIM_APDU_TRESPONSE2(RcvBuf, iRecvLen, head,VS);
			break;
		case INTERNAL_AUTHENTICATE:
			VUSIM_APDU_AUTHENTICATE2(RcvBuf, iRecvLen, head, VS, flag);
			break;
		case UPDATE_BINARY:
		case UPDATE_RECORD:
			VUSIM_APDU_UPDATE2(RcvBuf, iRecvLen, head,VS);
			break;
		case MANAGE_CHANNEL:
			VUSIM_APDU_MANAGE_CHANNEL_PROC2(RcvBuf, iRecvLen, head,VS);
			break;
		default:
			DBUG("[VUSIM_APDU_PROC2]ERROR DATA INS:%d\n", head->INS);//YYH TEST
			break;
	}

	return ;
}


static void VUSIM_APDU_PROC(unsigned char *RcvBuf, int iRecvLen, APDU_HEAD * head, VUSIM_STA *VS, int *flag)
{
	switch(head->INS)
	{
		case SELECT_FILE:
			VUSIM_APDU_SELECTFILE2(RcvBuf, iRecvLen, head,VS);
			break;
		case TERMINAL_PROFILE:
            VS->USAT_Flag=1;//TRUE;
			VUSIM_APDU_TERMINAL_PROFILE2(RcvBuf, iRecvLen, head,VS);
			break;
		case TERMINAL_RESPONSE:
			VUSIM_APDU_TRESPONSE2(RcvBuf, iRecvLen, head,VS);
			break;
		case INTERNAL_AUTHENTICATE:
			VUSIM_APDU_AUTHENTICATE2(RcvBuf, iRecvLen, head, VS, flag);
			break;
		case UPDATE_BINARY:
		case UPDATE_RECORD:
			VUSIM_APDU_UPDATE2(RcvBuf, iRecvLen, head,VS);
			break;
		case MANAGE_CHANNEL:
			VUSIM_APDU_MANAGE_CHANNEL_PROC2(RcvBuf, iRecvLen, head,VS);
			break;

		case GET_RESPONSE://C0
			VUSIM_APDU_GETRESPONSE(head,VS);
			break;

		case READ_BINARY: //B0
		case READ_RECORD: //B2
			VUSIM_APDU_READ(head,VS);
			break;

		case VERIFY:
			VUSIM_APDU_VERIFY(head,VS);
			break;

		case UNBLOCK_PIN:
			VUSIM_APDU_UNBLOCK(head,VS);
			break;

		case STATUS:
			VUSIM_APDU_STATUS(head,VS);
			break;

		case FETCH:
			VUSIM_APDU_FETCH(head,VS);
			break;
		//case UPDATE_BINARY:
		//case UPDATE_RECORD:
		//	VUSIM_APDU_UPDATE1(head,VS);
		//	break;
		//case MANAGE_CHANNEL:
		//	VUSIM_APDU_MANAGE_CHANNEL_PROC1(head,VS);
		//	break;

	    case 0xA2:
			VS->SW[0] = 0x6A;
			VS->SW[1] = 0x83;
			VUSIM_RetData(VS->SW, 2);
			break;
		default:
			DBUG("[VUSIM_APDU_PROC2]ERROR DATA INS:%x\n", head->INS);//YYH TEST
			VS->SW[0] = 0x6A;
			VS->SW[1] = 0x83;
			VUSIM_RetData(VS->SW, 2);

			break;
	}

	return ;
}

int VUSIM_MAIN_PROC(unsigned char *Buf, int iLen, int *flag)
{
	int status = 0;
	APDU_HEAD *p_head = &Data.APDUhead;
	VUSIM_STA * vs = &Data.VUSIM_Global;

	if((Buf == NULL)||(iLen <= 0))
	{
		DBUG( "[VUSIM_MAIN_PROC]Para error\n");//YYH TEST
		return 0;
	}

	memcpy((unsigned char*)(p_head), Buf, 5);
	if(p_head->LcLe != (iLen - 5)  &&  iLen > 5)
	{
		DBUG("Error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		return -1;
	}
	VUSIM_APDU_PROC(Buf+5, p_head->LcLe, p_head, vs, flag);


/*
	switch(vs->APDU_STAGE)
	{
		case APDU_STAGE0:
			status = VUSIM_APDU_HeadDet(Buf, iLen);
			if (status <= 0)
				break;

			memcpy((unsigned char*)(p_head), Buf, 5);
			VUSIM_APDU_PROC1(p_head, vs);
			break;

		case APDU_STAGE1:
            status = VUSIM_APDU_HeadDet(Buf, iLen);
            if (status <= 0)
                break;
            memcpy((unsigned char*)(p_head), Buf, 5);
			VUSIM_APDU_PROC2(Buf, iLen, p_head, vs, flag);
			break;

		default:
			DBUG("[VUSIM_MAIN_PROC]ERROR DATA APDU_STAGE:%d\n",vs->APDU_STAGE);//YYH TEST
			break;
	}
*/
	return 0;
}
